package com.aceitunaproject.server.unit;

import java.awt.Point;
import java.util.logging.Logger;

import com.aceitunaproject.server.AceitunaContext;
import com.aceitunaproject.server.entity.settlement.Settlement;
import com.aceitunaproject.server.entity.unit.Unit;
import com.aceitunaproject.server.map.MapManager;
import com.aceitunaproject.server.map.MapTile;
import com.aceitunaproject.server.player.Player;
import com.aceitunaproject.server.specialability.SpecialAbility;

import com.aceitunaproject.shared.exceptions.gamerules.EnumIllegalAction;
import com.aceitunaproject.shared.exceptions.gamerules.IllegalActionException;
import com.sun.sgs.app.AppContext;

/**
 * Unit manager interface implementation
 * 
 * @author Maciej Miechowicz
 */
public class UnitManagerImpl implements UnitManager {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static final String UNIT_PREFIX = "UNIT";



	private long lastUnitID = 0;

	/**
	 * Creates a new instance of the manager
	 * 
	 * 
	 */
	public UnitManagerImpl() {

	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void moveUnit(Unit unit, int destinationX, int destinationY)
			throws IllegalActionException {
		Logger.getLogger(this.getClass().getName()).info(				"moving unit id " + unit.getId() + " to " + destinationX
						+ " , " + destinationY);
	
		int timeUnitCost = 0;

		AppContext.getDataManager().markForUpdate(unit);
		MapManager mapManager = AceitunaContext.getMapManager();

		MapTile currentTile = mapManager.getTile(unit.getCurrentPosition());
		MapTile newTile = mapManager.getTile(destinationX, destinationY);
		if (currentTile != null) {
			
			
			if(!newTile.unitCanOccupyTile(unit))
			{
				throw new IllegalActionException(EnumIllegalAction.MOVE_TILE_INACCESIBLE_FOR_UNIT);
			}
			
			// destination tile must be adjacent to current tile
			if(!mapManager.getAdjacentTiles(currentTile).contains(newTile))
			{
				throw new IllegalActionException(EnumIllegalAction.MOVE_TILE_OUT_OF_RANGE);
			}
			
			timeUnitCost = newTile.getMovementCost(unit);
			// validates time units
			if (unit.getTimeUnits() < timeUnitCost) {
				throw new IllegalActionException(EnumIllegalAction.MOVE_UNIT_OUT_OF_TIME);
			}
			currentTile.removeUnit(unit.getId());
		}



		newTile.addUnit(unit.getId());

		unit.setCurrentPosition(new Point(destinationX, destinationY));

		if(unit.getInstallationBeingBuilt() != null)
		{
			AceitunaContext.getInstallationManager().getInstallation(unit.getInstallationBeingBuilt()).setBuildingUnit(null);
		}
		unit.subtractTimeUnits(timeUnitCost);
	}

	/**
	 * {@inheritDoc}
	 */
	public void moveUnit(long unitID, int destinationX, int destinationY)
			throws IllegalActionException {

		Unit unit = getUnit(unitID);

		moveUnit(unit, destinationX, destinationY);

	}

	@Override
	public Unit CreateUnit(String name, Player owner, Player controller) {

		/*Loyalty[] loyalties = new Loyalty[2];
		loyalties[0] = new Loyalty(owner,this);*/
		
		Unit newUnit = new Unit(lastUnitID, name, owner, controller);

		AppContext.getDataManager().setBinding(UNIT_PREFIX + lastUnitID,
				newUnit);
		lastUnitID++;
		return newUnit;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Unit getUnit(long unitID) {

		return (Unit) AppContext.getDataManager().getBinding(
				UNIT_PREFIX + unitID);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void buildSettlement(String name,Unit unit, int settlementX, int settlementY) throws IllegalActionException {
		
		
		//TODO: SETTLEMENT VALIDATIONS SHOULD BE IN SETTLEMENT MANAGER
		if(!unit.getCurrentPosition().equals(new Point(settlementX,settlementY)))
		{
			throw new IllegalActionException(EnumIllegalAction.BUILD_SETTLEMENT_MUST_BE_BUILT_IN_UNITS_CURRENT_POSITION);
		}
		if(!unit.HasAbility(SpecialAbility.BUILDSETTLEMENT))
		{
			throw new IllegalActionException(EnumIllegalAction.BUILD_SETTLEMENT_UNIT_DOES_NOT_HAVE_NEEDED_ABILITY);
		}
		
		if(!AceitunaContext.getMapManager().getTile(settlementX,settlementY).unitCanBuildSettlement(unit))
		{
			throw new IllegalActionException(EnumIllegalAction.BUILD_SETTLEMENT_SETTLEMENTS_CANNOT_BE_BUILT_IN_THIS_TILE);
		}
		AceitunaContext.getSettlementManager().buildSettlement(name, settlementX, settlementY, unit);
		unit.destroy();
		unit = null;
	}

	@Override
	public Unit recruitUnit(long settlementId, String name, int persons,
			Player player) throws IllegalActionException {
		
		Settlement settlement = AceitunaContext.getSettlementManager().getSettlement(settlementId);
		if(settlement.getPersons() < persons)
		{
			throw new IllegalActionException(EnumIllegalAction.RECRUIT_UNIT_SETTLEMENT_TOO_SMALL);
		}
		AppContext.getDataManager().markForUpdate(settlement);
		Unit theUnit = CreateUnit(name, player, player);
		moveUnit(theUnit, settlement.getCurrentPosition().x,  settlement.getCurrentPosition().y);
		theUnit.setPersons(persons);
		theUnit.setMorale(settlement.getMorale());
		
		//for test purposes
		theUnit.addEquipment(AceitunaContext.getEquipmentManager().getAllEquipments().get("SettlementBuildingEquipment"));
		
		settlement.setPersons(settlement.getPersons()-persons);
		
		return theUnit;
		
	}


}